home *** CD-ROM | disk | FTP | other *** search
- ;;; subr.el --- basic lisp subroutines for XEmacs
-
- ;;; Copyright (C) 1985, 1986, 1992, 1994 Free Software Foundation, Inc.
- ;;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
- ;;; Copyright (C) 1995 Sun Microsystems.
-
- ;; This file is part of XEmacs.
-
- ;; XEmacs is free software; you can redistribute it and/or modify it
- ;; under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 2, or (at your option)
- ;; any later version.
-
- ;; XEmacs is distributed in the hope that it will be useful, but
- ;; WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;; General Public License for more details.
-
- ;; You should have received a copy of the GNU General Public License
- ;; along with XEmacs; see the file COPYING. If not, write to the Free
- ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ;;; Synched up with: FSF 19.28.
-
- ;;; Code:
-
-
- ;;;; Lisp language features.
-
- (defmacro lambda (&rest cdr)
- "Return a lambda expression.
- A call of the form (lambda ARGS DOCSTRING INTERACTIVE BODY) is
- self-quoting; the result of evaluating the lambda expression is the
- expression itself. The lambda expression may then be treated as a
- function, i. e. stored as the function value of a symbol, passed to
- funcall or mapcar, etcetera.
- ARGS should take the same form as an argument list for a `defun'.
- DOCSTRING should be a string, as described for `defun'. It may be omitted.
- INTERACTIVE should be a call to the function `interactive', which see.
- It may also be omitted.
- BODY should be a list of lisp expressions."
- ;; Note that this definition should not use backquotes; subr.el should not
- ;; depend on backquote.el.
- ;; #### - I don't see why. So long as backquote.el doesn't use anything
- ;; from subr.el, there's no problem with using backquotes here. --Stig
- (list 'function (cons 'lambda cdr)))
-
- ;; FSF19 emits calls to defalias instead of fset in .elc files.
- (define-function 'defalias 'define-function)
- (define-function 'not 'null)
- (define-function 'eql 'eq)
- (if (not (fboundp 'numberp))
- (define-function 'numberp 'integerp)) ; different when floats
-
-
- ;;;; Hook manipulation functions.
-
- (defun run-hooks (&rest hooklist)
- "Takes hook names and runs each one in turn. Major mode functions use this.
- Each argument should be a symbol, a hook variable.
- These symbols are processed in the order specified.
- If a hook symbol has a non-nil value, that value may be a function
- or a list of functions to be called to run the hook.
- If the value is a function, it is called with no arguments.
- If it is a list, the elements are called, in order, with no arguments."
- (while hooklist
- (let ((sym (car hooklist)))
- (and (boundp sym)
- (symbol-value sym)
- (let ((value (symbol-value sym)))
- (if (and (listp value) (not (eq (car value) 'lambda)))
- (while value
- (funcall (car value))
- (setq value (cdr value)))
- (funcall value)))))
- (setq hooklist (cdr hooklist))))
-
- ;; FSFmacs says:
- ;; It is best not to depend on the value return by `run-hook-with-args',
- ;; as that may change.
-
- (defun run-hook-with-args (hook &rest args)
- "Run HOOK with the specified arguments ARGS.
- HOOK should be a symbol, a hook variable. If HOOK has a non-nil
- value, that value may be a function or a list of functions to be
- called to run the hook. If the value is a function, it is called with
- the given arguments and its return value is returned. If it is a
- list, the elements are called, in order, with the given arguments,
- and a list of the each function's return value is returned."
- (and (boundp hook)
- (symbol-value hook)
- (let ((value (symbol-value hook)))
- (if (and (listp value) (not (eq (car value) 'lambda)))
- (mapcar #'(lambda (foo) (apply foo args))
- value)
- (apply value args)))))
-
- (defun run-special-hook-with-args (hook &rest args)
- "Run HOOK with the specified arguments, returning the first non-nil value.
- HOOK should be a symbol, a hook variable. If HOOK has a non-nil
- value, that value may be a function or a list of functions to be
- called to run the hook. If the value is a function, it is called with
- the given arguments and its return value is returned. If it is a
- list, the elements are called, in order, with the given arguments,
- until one of them returns non-nil, and this value is returned."
- (and (boundp hook)
- (symbol-value hook)
- (let ((value (symbol-value hook)))
- (if (and (listp value) (not (eq (car value) 'lambda)))
- (let (retval)
- (while (and value
- (not (setq retval (apply (car value) args))))
- (setq value (cdr value)))
- retval)
- (apply value args)))))
-
- ;; Tell C code how to call this function.
- (setq run-hooks 'run-hooks)
-
- (defun add-hook (hook function &optional append)
- "Add to the value of HOOK the function FUNCTION.
- FUNCTION is not added if already present.
- FUNCTION is added (if necessary) at the beginning of the hook list
- unless the optional argument APPEND is non-nil, in which case
- FUNCTION is added at the end.
-
- HOOK should be a symbol, and FUNCTION may be any valid function. If
- HOOK is void, it is first set to nil. If HOOK's value is a single
- function, it is changed to a list of functions."
- ;(interactive "SAdd to hook-var (symbol): \naAdd which function to %s? ")
- (if (not (boundp hook)) (set hook nil))
- ;; If the hook value is a single function, turn it into a list.
- (let ((old (symbol-value hook)))
- (if (or (not (listp old)) (eq (car old) 'lambda))
- (setq old (list old)))
- (if (member function old)
- nil
- (set hook (if append
- (append old (list function)) ; don't nconc
- (cons function old))))))
-
- (defun remove-hook (hook function)
- "Remove from the value of HOOK the function FUNCTION.
- HOOK should be a symbol, and FUNCTION may be any valid function. If
- FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the
- list of hooks to run in HOOK, then nothing is done. See `add-hook'."
- (if (or (not (boundp hook)) ;unbound symbol, or
- (null (symbol-value hook)) ;value is nil, or
- (null function)) ;function is nil, then
- nil ;Do nothing.
- (let ((hook-value (symbol-value hook)))
- (if (consp hook-value)
- ;; don't side-effect the list
- (setq hook-value (delete function (copy-sequence hook-value)))
- (if (equal hook-value function)
- (setq hook-value nil)))
- (set hook hook-value))))
-
- ;; called by Fkill_buffer()
- (defvar kill-buffer-hook nil
- "Function or functions to be called when a buffer is killed.
- The value of this variable may be buffer-local.
- The buffer about to be killed is current when this hook is run.")
-
- ;; in C in FSFmacs
- (defvar kill-emacs-hook nil
- "Function or functions to be called when `kill-emacs' is called,
- just before emacs is actually killed.")
-
-
- ;;;; List functions.
-
- (defalias 'first 'car)
- (defalias 'rest 'cdr)
- (defalias 'endp 'null)
-
- (defsubst second (x)
- "Return the second element of the list LIST."
- (car (cdr x)))
-
- (defsubst third (x)
- "Return the third element of the list LIST."
- (car (cdr (cdr x))))
-
- (defsubst fourth (x)
- "Return the fourth element of the list LIST."
- (nth 3 x))
-
- (defsubst fifth (x)
- "Return the fifth element of the list LIST."
- (nth 4 x))
-
- (defsubst sixth (x)
- "Return the sixth element of the list LIST."
- (nth 5 x))
-
- (defsubst seventh (x)
- "Return the seventh element of the list LIST."
- (nth 6 x))
-
- (defsubst eighth (x)
- "Return the eighth element of the list LIST."
- (nth 7 x))
-
- (defsubst ninth (x)
- "Return the ninth element of the list LIST."
- (nth 8 x))
-
- (defsubst tenth (x)
- "Return the tenth element of the list LIST."
- (nth 9 x))
-
- (defsubst caar (x)
- "Return the `car' of the `car' of X."
- (car (car x)))
-
- (defsubst cadr (x)
- "Return the `car' of the `cdr' of X."
- (car (cdr x)))
-
- (defsubst cdar (x)
- "Return the `cdr' of the `car' of X."
- (cdr (car x)))
-
- (defsubst cddr (x)
- "Return the `cdr' of the `cdr' of X."
- (cdr (cdr x)))
-
- (defsubst caaar (x)
- "Return the `car' of the `car' of the `car' of X."
- (car (car (car x))))
-
- (defsubst caadr (x)
- "Return the `car' of the `car' of the `cdr' of X."
- (car (car (cdr x))))
-
- (defsubst cadar (x)
- "Return the `car' of the `cdr' of the `car' of X."
- (car (cdr (car x))))
-
- (defsubst caddr (x)
- "Return the `car' of the `cdr' of the `cdr' of X."
- (car (cdr (cdr x))))
-
- (defsubst cdaar (x)
- "Return the `cdr' of the `car' of the `car' of X."
- (cdr (car (car x))))
-
- (defsubst cdadr (x)
- "Return the `cdr' of the `car' of the `cdr' of X."
- (cdr (car (cdr x))))
-
- (defsubst cddar (x)
- "Return the `cdr' of the `cdr' of the `car' of X."
- (cdr (cdr (car x))))
-
- (defsubst cdddr (x)
- "Return the `cdr' of the `cdr' of the `cdr' of X."
- (cdr (cdr (cdr x))))
-
- (defsubst caaaar (x)
- "Return the `car' of the `car' of the `car' of the `car' of X."
- (car (car (car (car x)))))
-
- (defsubst caaadr (x)
- "Return the `car' of the `car' of the `car' of the `cdr' of X."
- (car (car (car (cdr x)))))
-
- (defsubst caadar (x)
- "Return the `car' of the `car' of the `cdr' of the `car' of X."
- (car (car (cdr (car x)))))
-
- (defsubst caaddr (x)
- "Return the `car' of the `car' of the `cdr' of the `cdr' of X."
- (car (car (cdr (cdr x)))))
-
- (defsubst cadaar (x)
- "Return the `car' of the `cdr' of the `car' of the `car' of X."
- (car (cdr (car (car x)))))
-
- (defsubst cadadr (x)
- "Return the `car' of the `cdr' of the `car' of the `cdr' of X."
- (car (cdr (car (cdr x)))))
-
- (defsubst caddar (x)
- "Return the `car' of the `cdr' of the `cdr' of the `car' of X."
- (car (cdr (cdr (car x)))))
-
- (defsubst cadddr (x)
- "Return the `car' of the `cdr' of the `cdr' of the `cdr' of X."
- (car (cdr (cdr (cdr x)))))
-
- (defsubst cdaaar (x)
- "Return the `cdr' of the `car' of the `car' of the `car' of X."
- (cdr (car (car (car x)))))
-
- (defsubst cdaadr (x)
- "Return the `cdr' of the `car' of the `car' of the `cdr' of X."
- (cdr (car (car (cdr x)))))
-
- (defsubst cdadar (x)
- "Return the `cdr' of the `car' of the `cdr' of the `car' of X."
- (cdr (car (cdr (car x)))))
-
- (defsubst cdaddr (x)
- "Return the `cdr' of the `car' of the `cdr' of the `cdr' of X."
- (cdr (car (cdr (cdr x)))))
-
- (defsubst cddaar (x)
- "Return the `cdr' of the `cdr' of the `car' of the `car' of X."
- (cdr (cdr (car (car x)))))
-
- (defsubst cddadr (x)
- "Return the `cdr' of the `cdr' of the `car' of the `cdr' of X."
- (cdr (cdr (car (cdr x)))))
-
- (defsubst cdddar (x)
- "Return the `cdr' of the `cdr' of the `cdr' of the `car' of X."
- (cdr (cdr (cdr (car x)))))
-
- (defsubst cddddr (x)
- "Return the `cdr' of the `cdr' of the `cdr' of the `cdr' of X."
- (cdr (cdr (cdr (cdr x)))))
-
- (defun last (x &optional n)
- "Returns the last link in the list LIST.
- With optional argument N, returns Nth-to-last link (default 1)."
- (if n
- (let ((m 0) (p x))
- (while (consp p) (setq m (1+ m)) (pop p))
- (if (<= n 0) p
- (if (< n m) (nthcdr (- m n) x) x)))
- (while (consp (cdr x)) (pop x))
- x))
-
- (defun butlast (x &optional n)
- "Returns a copy of LIST with the last N elements removed."
- (if (and n (<= n 0)) x
- (nbutlast (copy-sequence x) n)))
-
- (defun nbutlast (x &optional n)
- "Modifies LIST to remove the last N elements."
- (let ((m (length x)))
- (or n (setq n 1))
- (and (< n m)
- (progn
- (if (> n 0) (setcdr (nthcdr (- (1- m) n) x) nil))
- x))))
-
- ;;; these are just so convenient in while loops... The CL package will
- ;;; overload these with compatible but more powerful cousins.
-
- (defmacro push (val list)
- "Insert VAL at the head of LIST.
- Analogous to (setq LIST (cons VAL LIST))."
- `(setq ,list (cons ,val ,list)))
-
- (defmacro pop (list)
- "Remove and return the head of LIST.
- Analogous to (prog1 (car LIST) (setq LIST (cdr LIST)))."
- `(prog1 (car ,list) (setq ,list (cdr ,list))))
-
- ;; not obsolete.
- (define-function 'rplaca 'setcar)
- (define-function 'rplacd 'setcdr)
-
-
- ;;;; Mapping functions.
-
- (defun some (__predicate __seq)
- "Return true if PREDICATE is true of any element of SEQ.
- If so, return the true (non-nil) value returned by PREDICATE."
- (let ((__x nil))
- (while (and __seq
- (not (setq __x (funcall __predicate (pop __seq))))))
- __x))
-
- (defun every (__predicate __seq)
- "Return true if PREDICATE is true of every element of SEQ."
- (while (and __seq (funcall __predicate (car __seq)))
- (setq __seq (cdr __seq)))
- (null __seq))
-
- (defun notany (__predicate __seq)
- "Return true if PREDICATE is false of every element of SEQ."
- (not (apply 'some __predicate __seq)))
-
- (defun notevery (__predicate __seq)
- "Return true if PREDICATE is false of some element of SEQ."
- (not (apply 'every __predicate __seq)))
-
- (defun mapvector (__function __seq)
- "Apply FUNCTION to each element of SEQ, making a vector of the results.
- The result is a vector of the same length as SEQ.
- SEQ may be a list, a vector or a string."
- (let* ((len (length __seq))
- (vec (make-vector len 'nil))
- (i 0))
- (while (< i len)
- (aset vec i (funcall __function (cond ((listp __seq)
- (nth i __seq))
- (t (aref __seq i)))))
- (setq i (+ i 1)))
- vec))
-
-
- ;;;; Set functions -- less powerful equivalents of the Common Lisp ones.
-
- (defun adjoin (item list)
- "Add ITEM to LIST (unless it's already there) and return the new list."
- (if (memq item list) list (cons item list)))
-
- (defun union (list1 list2)
- "Return a list of elements that appear in either LIST1 or LIST2."
- (cond ((null list1) list2) ((null list2) list1)
- ((equal list1 list2) list1)
- (t
- (while list2
- (setq list1 (adjoin (car list2) list1))
- (setq list2 (cdr list2)))
- list1)))
-
- (defun intersection (list1 list2)
- "Return a list of elements that appear in both LIST1 and LIST2."
- (and list1 list2
- (if (equal list1 list2) list1
- (let ((result nil))
- (while list2
- (if (memq (car list2) list1)
- (setq result (cons (car list2) result)))
- (setq list2 (cdr list2)))
- result))))
-
- (defun set-difference (list1 list2)
- "Return a list of elements of LIST1 that do not appear in LIST2."
- (if (or (null list1) (null list2)) list1
- (let ((list1 (copy-sequence list1)))
- (while list2
- (setq list1 (delq (car list2) list1))
- (setq list2 (cdr list2)))
- list1)))
-
- (defun set-exclusive-or (list1 list2)
- "Return a list of elements that appear in exactly one of LIST1 and LIST2."
- (cond ((null list1) list2) ((null list2) list1)
- ((equal list1 list2) nil)
- (t (append (set-difference list1 list2)
- (set-difference list2 list1)))))
-
- (defun subsetp (list1 list2)
- "True if every element of LIST1 also appears in LIST2."
- (cond ((null list1) t) ((null list2) nil)
- ((equal list1 list2) t)
- (t (while (and list1
- (memq (car list1) list2))
- (setq list1 (cdr list1)))
- (null list1))))
-
- ;;;; String functions.
-
- (defun replace-in-string (str regexp newtext &optional literal)
- "Replaces all matches in STR for REGEXP with NEWTEXT string.
- Optional LITERAL non-nil means do a literal replacement.
- Otherwise treat \\ in NEWTEXT string as special:
- \\& means substitute original matched text,
- \\N means substitute match for \(...\) number N,
- \\\\ means insert one \\."
- (if (not (stringp str))
- (error "(replace-in-string): First argument must be a string: %s" str))
- (if (stringp newtext)
- nil
- (error "(replace-in-string): 3rd arg must be a string: %s"
- newtext))
- (let ((rtn-str "")
- (start 0)
- (special)
- match prev-start)
- (while (setq match (string-match regexp str start))
- (setq prev-start start
- start (match-end 0)
- rtn-str
- (concat
- rtn-str
- (substring str prev-start match)
- (cond (literal newtext)
- (t (mapconcat
- (function
- (lambda (c)
- (if special
- (progn
- (setq special nil)
- (cond ((eq c ?\\) "\\")
- ((eq c ?&)
- (substring str
- (match-beginning 0)
- (match-end 0)))
- ((and (>= c ?0) (<= c ?9))
- (if (> c (+ ?0 (length
- (match-data))))
- ;; Invalid match num
- (error "(replace-in-string) Invalid match num: %c" c)
- (setq c (- c ?0))
- (substring str
- (match-beginning c)
- (match-end c))))
- (t (char-to-string c))))
- (if (eq c ?\\) (progn (setq special t) nil)
- (char-to-string c)))))
- newtext ""))))))
- (concat rtn-str (substring str start))))
-
- (defun split-string (string pattern)
- "Return a list of substrings of STRING which are separated by PATTERN."
- (let (parts (start 0))
- (while (string-match pattern string start)
- (setq parts (cons (substring string start (match-beginning 0)) parts)
- start (match-end 0)))
- (nreverse (cons (substring string start) parts))
- ))
-
- (defmacro with-output-to-string (&rest forms)
- "Collect output to `standard-output' while evaluating FORMS and return
- it as a string."
- ;; by "William G. Dubuque" <wgd@zurich.ai.mit.edu> w/ mods from Stig
- (` (save-excursion
- (set-buffer (get-buffer-create " *string-output*"))
- (setq buffer-read-only nil)
- (buffer-disable-undo (current-buffer))
- (erase-buffer)
- (let ((standard-output (current-buffer)))
- (,@ forms))
- (prog1
- (buffer-string)
- (erase-buffer)))))
-
- (defun insert-face (string face)
- "Insert STRING and highlight with FACE. Returns the extent created."
- (let ((p (point)) ext)
- (insert string)
- (setq ext (make-extent p (point)))
- (set-extent-face ext face)
- ext))
-
- ;; not obsolete.
- (define-function 'string= 'string-equal)
- (define-function 'string< 'string-lessp)
- (define-function 'int-to-string 'number-to-string)
- (define-function 'string-to-int 'string-to-number)
-
-
- ;;;; Miscellanea.
-
- (defun ignore (&rest ignore)
- "Do nothing and return nil.
- This function accepts any number of arguments, but ignores them."
- (interactive)
- nil)
-
- (defun error (&rest args)
- "Signal an error, making error message by passing all args to `format'.
- This error is not continuable: you cannot continue execution after the
- error using the debugger `r' command. See also `cerror'."
- (while t
- (apply 'cerror args)))
-
- (defun cerror (&rest args)
- "Like `error' but signals a continuable error."
- (signal 'error (list (apply 'format args))))
-
- (defmacro check-argument-type (predicate argument)
- "Check that ARGUMENT satisfies PREDICATE.
- If not, signal a continuable `wrong-type-argument' error until the
- returned value satifies PREDICATE, and assign the returned value
- to ARGUMENT."
- `(if (not (,(eval predicate) ,argument))
- (setq ,argument
- (wrong-type-argument ,predicate ,argument))))
-
- (defmacro save-current-buffer (&rest forms)
- "Restore the current buffer setting after executing FORMS.
- Does not restore the values of point and mark.
- See also: `save-excursion'."
- ;; by Stig@hackvan.com
- (` (let ((_cur_buf_ (current-buffer)))
- (unwind-protect
- (progn (,@ forms))
- (set-buffer _cur_buf_)))))
-
- (defmacro eval-in-buffer (buffer &rest forms)
- "Evaluate FORMS in BUFFER.
- See also: `save-current-buffer' and `save-excursion'."
- ;; by Stig@hackvan.com
- (` (save-current-buffer
- (set-buffer (, buffer))
- (,@ forms))))
-
- ;;; The real defn is in abbrev.el but some early callers
- ;;; (eg lisp-mode-abbrev-table) want this before abbrev.el is loaded...
-
- (if (not (fboundp 'define-abbrev-table))
- (progn
- (setq abbrev-table-name-list '())
- (fset 'define-abbrev-table (function (lambda (name defs)
- ;; These are fixed-up when abbrev.el loads.
- (setq abbrev-table-name-list
- (cons (cons name defs)
- abbrev-table-name-list)))))))
-
- (defun functionp (obj)
- "Returns t if OBJ is a function, nil otherwise."
- (cond
- ((symbolp obj) (fboundp obj))
- ((subrp obj))
- ((compiled-function-p obj))
- ((consp obj)
- (if (eq (car obj) 'lambda) (listp (car (cdr obj)))))
- (t nil)))
-
- (defun add-to-list (list-var element)
- "Add to the value of LIST-VAR the element ELEMENT if it isn't there yet.
- If you want to use `add-to-list' on a variable that is not defined
- until a certain package is loaded, you should put the call to `add-to-list'
- into a hook function that will be run only after loading the package.
- Major mode hooks are one thing which can do the job."
- (or (member element (symbol-value list-var))
- (set list-var (cons element (symbol-value list-var)))))
-
- ;; This was not present before. I think Jamie had some objections
- ;; to this, so I'm leaving this undefined for now. --ben
-
- ;;; The objection is this: there is more than one way to load the same file.
- ;;; "foo", "foo.elc", "foo.el", and "/some/path/foo.elc" are all differrent
- ;;; ways to load the exact same code. `eval-after-load' is too stupid to
- ;;; deal with this sort of thing. If this sort of feature is desired, then
- ;;; it should work off of a hook on `provide'. Features are unique and
- ;;; the arguments to (load) are not. --Stig
-
- ;;;; Specifying things to do after certain files are loaded.
-
- ;(defun eval-after-load (file form)
- ; "Arrange that, if FILE is ever loaded, FORM will be run at that time.
- ;This makes or adds to an entry on `after-load-alist'.
- ;It does nothing if FORM is already on the list for FILE.
- ;FILE should be the name of a library, with no directory name."
- ; (or (assoc file after-load-alist)
- ; (setq after-load-alist (cons (list file) after-load-alist)))
- ; (let ((elt (assoc file after-load-alist)))
- ; (or (member form (cdr elt))
- ; (nconc elt (list form))))
- ; form)
- ;
- ;(defun eval-next-after-load (file)
- ; "Read the following input sexp, and run it whenever FILE is loaded.
- ;This makes or adds to an entry on `after-load-alist'.
- ;FILE should be the name of a library, with no directory name."
- ; (eval-after-load file (read)))
-
- ; alternate names (not obsolete)
- (if (not (fboundp 'mod)) (define-function 'mod '%))
- (define-function 'move-marker 'set-marker)
- (define-function 'beep 'ding) ;preserve lingual purtity
- (define-function 'indent-to-column 'indent-to)
- (define-function 'backward-delete-char 'delete-backward-char)
- (define-function 'search-forward-regexp (symbol-function 're-search-forward))
- (define-function 'search-backward-regexp (symbol-function 're-search-backward))
- (define-function 'remove-directory 'delete-directory)
- (define-function 'set-match-data 'store-match-data)
- (define-function 'send-string-to-terminal 'external-debugging-output)
- (define-function 'buffer-string 'buffer-substring)
-